Skip to content

Fix specular mapping with linear blend regime#1941

Open
slipher wants to merge 1 commit intoDaemonEngine:for-0.56.0/syncfrom
slipher:linear-specular
Open

Fix specular mapping with linear blend regime#1941
slipher wants to merge 1 commit intoDaemonEngine:for-0.56.0/syncfrom
slipher:linear-specular

Conversation

@slipher
Copy link
Member

@slipher slipher commented Mar 20, 2026

The default behavior was to convert specular maps from sRGB to linear colorspace when using the linear blend regime. But for most of our assets, doing sRGB conversion of specular maps (when in the linear blend regime) looks almost the same as disabling specular mapping, while loading them as-is looks fairly comparable to naive mode. So don't do the conversion.

Here are some screenshots, with tonemapping off for easier comparison, of the scene discussed at Unvanquished/Unvanquished#3446 (comment).

NAIVE (via r_forceBlendRegime)

unvanquished-chasm-flake-1

LINEAR (before)

unvanquished-chasm-flake-1

LINEAR (after)

unvanquished-chasm-flake-1

The wall under the light here is a nice easy-to-see example:

NAIVE (via r_forceBlendRegime

unvanquished-chasm-light-shortrange

LINEAR (before)

unvanquished-chasm-light-shortrange

LINEAR (after)

unvanquished-chasm-light-shortrange

The default behavior was to convert specular maps from sRGB to linear
colorspace when using the linear blend regime. But for most of our
assets, doing sRGB conversion of specular maps (when in the linear blend
regime) looks almost the same as disabling specular mapping, while
loading them as-is looks fairly comparable to naive mode.  So don't do
the conversion.
@illwieckz
Copy link
Member

Please keep the mechanism to switch the specular map colorspace, just revert the default.

Specular maps from tex-ex need to be linearized, as seen on those walls, it is obviously wrong to load those specular maps the linear way:

unvanquished_2026-03-21_001902_000

unvanquished_2026-03-21_001927_000

I'll add a sloth keyword to make Sloth add the related keyword to the shader.

So we better configure some texture sets for one format.

@illwieckz
Copy link
Member

Those ex textures are also used on parpax and yocto.

unvanquished_2026-03-21_003649_000

unvanquished_2026-03-21_003700_000

@illwieckz
Copy link
Member

We probably have to load as sRGB all texture sets by evillair. The textures in chasm are by phillipk.

@illwieckz
Copy link
Member

The ”base” texture from the Vega set also has a too strong specular map when not linearized:

unvanquished_2026-03-21_004413_000

Some textures like this panel features this texture:

unvanquished_2026-03-21_004223_000

@illwieckz
Copy link
Member

Another usage of ex in thunder:

unvanquished_2026-03-21_004606_000

@illwieckz
Copy link
Member

Actually chasm uses pk02, pk01 needs to be linearized, as seen in antares:

unvanquished_2026-03-21_004932_000

@illwieckz
Copy link
Member

illwieckz commented Mar 20, 2026

Like pk02, we can probably load without conversion the specular map from ej01, it looks good:

unvanquished_2026-03-21_005108_000

@illwieckz
Copy link
Member

pk01 again, in station15, needs linearization:

unvanquished_2026-03-21_005402_000

@illwieckz
Copy link
Member

Those black squares in the middle are pk01, need linearization:

unvanquished_2026-03-21_005616_000

@illwieckz
Copy link
Member

Those walls are tech texture set! A bit strong but not too much, maybe fine loaded without conversion:

unvanquished_2026-03-21_005700_000

The tech texture set was made for UE3 if I'm right.

@illwieckz
Copy link
Member

illwieckz commented Mar 21, 2026

This is trak5, maybe can be loaded without conversion:

unvanquished_2026-03-21_005844_000

@illwieckz
Copy link
Member

In spacetracks, those two floor textures are from pk02, a bit strong, maybe OK that way (without conversion);

unvanquished_2026-03-21_010439_000

@illwieckz
Copy link
Member

Floor texture on the left: pk02, floor texture on the right: trak5.

Loading without color conversion make them strong, maybe OK though. At least they're consistent:

unvanquished_2026-03-21_010510_000

@illwieckz
Copy link
Member

This wall in spacetracks is tech again, strong, but maybe not bad (no color conversion)

unvanquished_2026-03-21_010627_000

@illwieckz
Copy link
Member

illwieckz commented Mar 21, 2026

So we may do:

  • ex: sRGB
  • pk01: sRGB
  • pk02: linear
  • trak5: linear
  • tech: linear
  • ej01: linear
  • vega: sRGB

We may also selectively convert textures from vega, but not all.

@illwieckz
Copy link
Member

Though the specularity may be too strong with this one (on the door, pk02, not converted):

unvanquished_2026-03-21_011253_000

@illwieckz
Copy link
Member

Some documentation showing that there are mixed usage of linar and sRGB space for specular maps:

Specular/Reflection/Reflectivity maps generally are Gamma space.
-- https://fr.scribd.com/document/369235157/Physically-Based-Rendering-Encyclopedia

About that document I just quoted, it talks about specular maps and gloss maps, while Xonotic names specular maps gloss maps, in that document, gloss maps are rougness maps (for PBR). In this document it looks like what they call specular is what we call specular.

To avoid this we need to apply some gamma correction to the colors : (pow(color, gamma); This only apply to textures that will render colors on screen (basically diffuse map, specular, light maps). Normal maps, height maps don’t need the correction.
-- https://wiki.jmonkeyengine.org/docs/3.4/core/system/jme3_srgbpipeline.html

Here what's said on light on that last quote may be specific to that engine (basically doing like q3map2 -sRGB), but the specular map isn't supposed to be engine-specific.

Textures used for retrieving lighting parameters (like specular maps and normal maps) are almost always in linear space
-- https://learnopengl.com/Advanced-Lighting/Gamma-Correction

Now this one contradicts the previous ones.

The reason seems simple: early specular maps were likely done in authoring tools and for engines not caring about colorspace. But as time goes, workflows became corrected. The more in industry practics we come close to what will become PBR, the more we can expect linear specular maps.

We can rephrase it: Textures used for retrieving lighting parameters should be in linear space. But it looks like the practice was different.

@illwieckz
Copy link
Member

illwieckz commented Mar 21, 2026

For information in my early implementations of the linear pipeline, I was loading all specular maps in linear space. My first iterations of my sRGB testing server was loading all specular maps in linear space (like your branch does), but then based on feedback I switched them for loading as sRGB.

@illwieckz
Copy link
Member

illwieckz commented Mar 21, 2026

This map makes obvious assuming that all specular maps are linear may be a bad idea:

@illwieckz
Copy link
Member

Here is a quote from a previous detailed comment of mine on the topic:

There is one remaining question… is specular map in linear space or in sRGB space?

As it's part of a compute, I would expect linear, but in fact maybe not.

In fact, some standard require specular+gloss files to store specular in sRGB space and gloss in linear space (given our own specular+gloss files are putting specular in RGB chanels and gloss in Alpha channel and Alpha is always linear, it makes sense to have such Alpha channel colorspace as no builtin conversion exist for the Alpha channel):
https://kcoley.github.io/glTF/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/

In our situation, I tested rendering maps and models assuming all specular maps were in sRGB or in linear space.

  • It happens that most of our map textures render far better if we assume their specular maps are in sRGB space. This is very obvious with some texture sets like the ones used in re-textured arachnid2, some textures look obviously broken if their specular maps are considered in linear space.
  • Most of our model textures render far better if we assume they are in sRGB space, some textures look obviously broken if their specular maps are considered in linear space (for example: the egg).
  • Some of our model textures render better if we assume they are in linear space (for example: the overmind).
  • Assuming every specular map is in linear space makes textures obviously broken if they may have been supposed to be in sRGB space.
  • Assuming every specular map is in sRGB space makes textures a bit dull but not obviously broken if they may have been supposed to be in linear space.
  • Some textures like the creep may always look bad whatever colorspace is assumed, given some envionment (like the creep in arachnid2 alien base).
    -- renderer: implement native sRGB support #1687 (comment)

The document I linked at the time said:

specularFactor

The specular RGB color of the material. This value is linear.

glossinessFactor

The glossiness or smoothness of the material. A value of 1.0 means the material has full glossiness or is perfectly smooth. A value of 0.0 means the material has no glossiness or is perfectly rough. This value is linear.

specularGlossinessTexture

The specular-glossiness texture is a RGBA texture, containing the specular color (RGB) in sRGB space and the glossiness value (A) in linear space.

https://kcoley.github.io/glTF/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness/

In that document, the specular map is stored in sRGB space, only the factor is in linear space, which makes sense, we better not multiply an sRGB factor.

As I said at the time in the other thread, we even have some of those RGBA specular maps, and I do believe they are specular+glossiness as the quote from our about page that says « Support […] gloss, specular […] maps » is very old (maybe even older than me contributing to Unvanquished).

This sentence was reworded by me from time to time, but that gloss mention wasn't added by me. All I did was to carry that gloss mention over, sometime not knowing (yet) what it meant but observing a conservative approach in writing, just in case, to not lose the information that predated my efforts.

@slipher
Copy link
Member Author

slipher commented Mar 21, 2026

Please keep the mechanism to switch the specular map colorspace, just revert the default.

What should the shader keywords be? Since the keywords were designed as a button that that can only be pushed one way, one must think of a new set of keywords when changing the default...

@illwieckz
Copy link
Member

I'm not sure this is a good idea to change the default. It looks like we're deciding to change the whole because of a single rock texture.

@illwieckz
Copy link
Member

illwieckz commented Mar 21, 2026

As a remind, we switched to “sRGB specular map as default” after testing “linear specular map as default” and finding that “sRGB specular map as default” was statistically more correct with our corpus. Then we added keywords to allow us to switch that per-shader if such need surfaces. That rock may be a good candidate for that.

@slipher
Copy link
Member Author

slipher commented Mar 21, 2026

I'm not sure this is a good idea to change the default. It looks like we're deciding to change the whole because of a single rock texture.

Well I gave a second example from Chasm so hopefully it was at least because of a single texture set :)

I checked a few of those station15 ones for consistency with the naive render and your conclusions seem reasonable.

@illwieckz
Copy link
Member

For the comparison in corridor, we should remind that the naive look cannot fully be used as a reference of correctness to begin with. Some of our textures even been designed for other game engines (like Unreal Engine for the tech set), and we may have been wrong with them from the start. Trying to reproduce the old look just for the sake of reproducing the old look may encourage us to introduce bugs.

The pk02 rock looks better when assumed linear, but I'm not sure that's what to do with others from the same texture set.

I shown this pk02 door on spacetracks:

unvanquished_2026-03-21_011253_000

But we can also look that pk02 wall on spacetracks:

unvanquished_2026-03-21_052134_000

Light reflection may be too strong.

@illwieckz
Copy link
Member

According to philipk.net, the pk01 and pk02 texture sets were done for idTech4. I wonder what iTech4 did, I even don't know if they did colorspace correction at all…

@illwieckz
Copy link
Member

More precisely, according to the readme in the zips, they were made for Quake IV.

@illwieckz
Copy link
Member

So I did some research, and it looks like id Tech 4 and Quake 4 were just doing it the naive way, using similar gamma ramp trick like Quake 3 at the end of the pipeline, so basically not linearizing any input. But then the PK texture packs themselves were never meant to be used as “all linear specular maps” or “all sRGB specular maps”, we may have to evaluate them per texture, not just per texture set.

@slipher
Copy link
Member Author

slipher commented Mar 21, 2026

Some of our textures even been designed for other game engines (like Unreal Engine for the tech set), and we may have been wrong with them from the start.

Hoping that it looks like another engine by just picking the colorspace is probably hopeless since there are a bunch of tunable parameters with specular exponent etc. and they are probably different. Though I think it is possible to customize those with shader keywords. For me the point of reference is just whether it looks like what the mapper saw when placing the texture in their map.

@slipher
Copy link
Member Author

slipher commented Mar 21, 2026

In the end maybe we are just using the colorspace as a blunt instrument for making things brighter/dimmer, like the colorspace with colormaps that use blendfunc add. But at least with specular maps there are more tools to experiment with finer adjustments. r_specularScale can be used to set a global linear multiplier for the specular map. Also the gloss channel can be rescaled with r_specularExponentMin/r_specularExponentMax and there are shader keywords to set that on a per-shader basis. Note that if there is no alpha it will use max "glossiness", i.e. the view direction must line up more with the light direction to see specular highlights.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants